package com.edgegateway.web.controller.iot;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.edgegateway.common.pk.IdWorker;
import com.edgegateway.common.utils.StringUtils;
import com.edgegateway.common.utils.http.BaseAuthHttpUtils;
import com.edgegateway.system.domain.IotRuleFlow;
import com.edgegateway.system.domain.NanoMQ;
import com.edgegateway.system.service.IIotRuleFlowService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import com.edgegateway.common.annotation.Log;
import com.edgegateway.common.enums.BusinessType;
import com.edgegateway.system.domain.IotEdgeDevices;
import com.edgegateway.system.service.IIotEdgeDevicesService;
import com.edgegateway.common.core.controller.BaseController;
import com.edgegateway.common.core.domain.AjaxResult;
import com.edgegateway.common.utils.poi.ExcelUtil;
import com.edgegateway.common.core.page.TableDataInfo;

import javax.validation.Valid;

/**
 * 边缘设备Controller
 * 
 * @author ruoyi
 * @date 2023-01-03
 */
@Api("边缘设备")
@Controller
@RequestMapping("/system/devices")
public class IotEdgeDevicesController extends BaseController
{
    private String prefix = "iot/devices";


    @Value("${mqtt.api-url}")
    private String API_URL;
    @Value("${mqtt.edge-topic}")
    private String EDGE_TOPIC;

    @Autowired
    private IIotEdgeDevicesService iotEdgeDevicesService;

    @Autowired
    private IIotRuleFlowService iotRuleFlowService;

    @Autowired
    private IdWorker idWorker;

    @RequiresPermissions("system:devices:view")
    @GetMapping()
    public String devices()
    {
        return prefix + "/devices";
    }

    /**
     * 查询边缘设备列表
     */
    @RequiresPermissions("system:devices:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(IotEdgeDevices iotEdgeDevices)
    {
        startPage();
        List<IotEdgeDevices> list = iotEdgeDevicesService.selectIotEdgeDevicesList(iotEdgeDevices);
        devicesAcync();
        return getDataTable(list);
    }

    /**
     * 导出边缘设备列表
     */
    @RequiresPermissions("system:devices:export")
    @Log(title = "边缘设备", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(IotEdgeDevices iotEdgeDevices)
    {
        List<IotEdgeDevices> list = iotEdgeDevicesService.selectIotEdgeDevicesList(iotEdgeDevices);
        ExcelUtil<IotEdgeDevices> util = new ExcelUtil<IotEdgeDevices>(IotEdgeDevices.class);
        return util.exportExcel(list, "边缘设备数据");
    }

    /**
     * 新增边缘设备
     */
    @GetMapping("/add")
    public String add()
    {
        return prefix + "/add";
    }

    /**
     * 新增保存边缘设备
     */
    @RequiresPermissions("system:devices:add")
    @Log(title = "边缘设备", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(IotEdgeDevices iotEdgeDevices)
    {
        return toAjax(iotEdgeDevicesService.insertIotEdgeDevices(iotEdgeDevices));
    }

    /**
     * 修改边缘设备
     */
    @RequiresPermissions("system:devices:edit")
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable("id") String id, ModelMap mmap)
    {
        IotEdgeDevices iotEdgeDevices = iotEdgeDevicesService.selectIotEdgeDevicesById(id);
        mmap.put("iotEdgeDevices", iotEdgeDevices);
        return prefix + "/edit";
    }

    /**
     * 修改保存边缘设备
     */
    @RequiresPermissions("system:devices:edit")
    @Log(title = "边缘设备", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(IotEdgeDevices iotEdgeDevices)
    {
        return toAjax(iotEdgeDevicesService.updateIotEdgeDevices(iotEdgeDevices));
    }

    /**
     * 删除边缘设备
     */
    @RequiresPermissions("system:devices:remove")
    @Log(title = "边缘设备", businessType = BusinessType.DELETE)
    @PostMapping( "/remove")
    @ResponseBody
    public AjaxResult remove(String ids)
    {
        return toAjax(iotEdgeDevicesService.deleteIotEdgeDevicesByIds(ids));
    }

    @GetMapping("/dyList/{id}")
    public String dyList(@PathVariable("id") String id, ModelMap mmap)
    {
        mmap.put("deviceId",id);
        return prefix + "/subscribe";
    }

    @PostMapping("/subscribeList/{id}")
    @ResponseBody
    public TableDataInfo subscribeList(@PathVariable String id){
        startPage();
        IotEdgeDevices iotEdgeDevices = iotEdgeDevicesService.selectIotEdgeDevicesById(id);
        String result = BaseAuthHttpUtils.httpURLConnectionGet(API_URL+"subscriptions/");
        List<NanoMQ> subscriptions = new ArrayList<>();
        if(StringUtils.isNotBlank(result)) {
            JSONArray arr = JSONArray.parseArray((JSONObject.parseObject(result)).getString("data"));
            subscriptions = JSONArray.parseArray(arr.toJSONString(), NanoMQ.class);
            subscriptions = subscriptions.stream().filter(o -> o.getTopic().indexOf(iotEdgeDevices.getTopic()) == 0).collect(Collectors.toList());
        }
        return getDataTable(subscriptions);
    }

    @GetMapping("/devInfo/{id}")
    public String devInfo(@PathVariable("id") String id, ModelMap mmap)
    {
        IotEdgeDevices device = iotEdgeDevicesService.selectIotEdgeDevicesById(id);
        mmap.put("device",device);
        return prefix + "/info";
    }


    /**
     * 跟随列表刷新进行更新
     * 边缘设备同步
     */
    public void devices2Acync (List<IotEdgeDevices> iotEdgeDevicesList){
        String result = BaseAuthHttpUtils.httpURLConnectionGet(API_URL+"subscriptions/");
        if(StringUtils.isNotBlank(result)) {
            ArrayList<String> list = new ArrayList<>();
            JSONArray arr = JSONArray.parseArray((JSONObject.parseObject(result)).getString("data"));
            List<NanoMQ> subscriptions = JSONArray.parseArray(arr.toJSONString(), NanoMQ.class);
            subscriptions = subscriptions.stream().filter(o -> o.getTopic().indexOf(EDGE_TOPIC) == 0).collect(Collectors.toList());

            List<String> collect = iotEdgeDevicesList.stream().map(IotEdgeDevices::getTopic).collect(Collectors.toList());
            for (IotEdgeDevices devices:iotEdgeDevicesList) {
                for (NanoMQ s:subscriptions) {
                    if(s.getTopic().indexOf(devices.getTopic())==0){
                        if(devices.getStatus()==0){
                            devices.setStatus(1);
                            iotEdgeDevicesService.updateIotEdgeDevices(devices);
                        }
                        collect.remove(devices.getTopic());
                    }else {
                        devices.setStatus(0);
                    }
                }
                devices.getTopic();
            }
            if(collect.size() > 0){
                for (String tpoic:collect) {
                    iotEdgeDevicesService.updateByTopic(tpoic);
                }
            }
        }
    }

    /**
     * 手动同步
     * @return
     */
    @ApiOperation(value = "同步边缘设备", notes = "同步边缘设备信息")
    @GetMapping(value = "/async")
    public AjaxResult async() {
        int count = devicesAcync();
        return AjaxResult.success("共同步"+count+"条数据");
    }

    /**
     * 自动
     * 边缘设备同步
     */
    @Scheduled(cron = "${spring.mqtt.cron}")
    public int devicesAcync (){
        int count = 0;
        //边缘设备统一主题开头
        //String edgeTopic = "iot-node/";  //统一主题     iot-node/边缘实力code/设备标识/xxx/...
        //获取所有边缘网关主题

        String result = BaseAuthHttpUtils.httpURLConnectionGet(API_URL+"subscriptions/");
        if(StringUtils.isNotBlank(result)){
            ArrayList<String> list = new ArrayList<>();
            JSONArray arr = JSONArray.parseArray((JSONObject.parseObject(result)).getString("data"));
            List<NanoMQ> subscriptions = JSONArray.parseArray(arr.toJSONString(), NanoMQ.class);
            subscriptions = subscriptions.stream().filter(o -> o.getTopic().indexOf(EDGE_TOPIC) == 0).collect(Collectors.toList());

            List<String> topics = subscriptions.stream().map(NanoMQ::getTopic).distinct().collect(Collectors.toList());
            for (int i=0;i<topics.size();i++) {
                String[] split = topics.get(i).split("/");
                topics.set(i,"/"+ split[1] +"/"+ split[2] +"/"+ split[3]);
            }
            List<IotEdgeDevices> edgeDevicesList = iotEdgeDevicesService.getAll();
            if(topics.size()<1 && edgeDevicesList.size()<1) return count;
            List<String> collect = edgeDevicesList.stream().map(IotEdgeDevices::getTopic).collect(Collectors.toList());
            if(subscriptions.size()>0){
                for (NanoMQ subscription: subscriptions) {
                    String[] split = subscription.getTopic().split("/");
                    if(split.length<4) break; //格式不正确
                    String topic = "/"+ split[1] +"/"+ split[2] +"/"+ split[3];
                    collect.remove(topic);
                    edgeDevicesList.removeIf(o->o.getTopic().equals(topic));
                    IotEdgeDevices devices = iotEdgeDevicesService.getTopic(topic);
                    if(devices == null) devices = new IotEdgeDevices();
                    devices.setTopic(topic);
                    devices.setClientId(subscription.getClientid());
                    //通过编码code获取边缘网关信息
                    //EdgeGateway gateway = edgeGatewayService.getGateWay(split[1]);
                    IotRuleFlow flow = iotRuleFlowService.getIotRuleFlowByFlowId(split[2]);
                    if(flow == null) break;
                    devices.setGatewayId(flow.getEdgeGatewayId());
                    devices.setRuleFlowId(flow.getId());
                    //设置部署时间及客户端id
                    //获取客户端信息
                    String r = BaseAuthHttpUtils.httpURLConnectionGet(API_URL + "clients/" + subscription.getClientid());
                    JSONArray data = JSONArray.parseArray((JSONObject.parseObject(r)).getString("data"));
                    if(data.size()>0){
                        JSONObject res = JSONObject.parseObject(data.get(0).toString());
                        String connected = res.getString("conn_state");
                        if(connected.equals("connected")) devices.setStatus(1);
                        //Date createdAt = res.getDate("created_at");
                        //devices.setDeployTime(createdAt);
                    }
                    if(devices.getId() == null){
                        //设备默认设备名
                        devices.setDevicesName("边缘设备"+new Date().getTime());
                        devices.setId(idWorker.nextId());
                        devices.setDeployTime(new Date());
                        iotEdgeDevicesService.insertIotEdgeDevices(devices);
                        count++;
                    }else {
                        iotEdgeDevicesService.updateIotEdgeDevices(devices);
                        count++;
                    }
                }
                if(collect.size() > 0 ){
                    for (int i = 0;i<collect.size();i++) {
                        if(edgeDevicesList.get(i).getStatus()==1){
                            iotEdgeDevicesService.updateByTopic(collect.get(i));
                            count++;
                        }
                    }
                }
            }else {
                iotEdgeDevicesService.updateList(edgeDevicesList);
                count+=edgeDevicesList.size();
            }

        }
        return count;
    }


}
